﻿using System;
using System.Collections.Generic;
using DIT.Contract;
using DIT.DB.Database;
using DIT.Domain;
using System.Data;
using System.Linq;

namespace DIT.DB.DAL
{
    public class DITRepository : IRepository
    {
        private readonly DatabaseBase database;

        public DITRepository(DatabaseBase database)
        {
            if (database == null)
                throw new ArgumentNullException("database");
            this.database = database;
        }

        public bool BulkInsert<T>(IEnumerable<T> entityList) where T : DomainBase
        {
            if (entityList == null)
                throw new ArgumentNullException("entityList");
            int rowsInsertedActual = 0;
            int rowsInsertedExpected = 0;
            foreach (T entity in entityList)
            {
                rowsInsertedExpected++;
                rowsInsertedActual += database.ExecuteNonQuery(DataMapper.InsertCommand<T>());
            }
            return rowsInsertedActual == rowsInsertedExpected;
        }

        public Guid Insert<T>(T entity) where T : DomainBase
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            entity.ID = NewID();
            return database.ExecuteNonQuery(DataMapper.InsertCommand<T>()) == 1 ? entity.ID : Guid.Empty;
        }
        private Guid NewID()
        {
            Guid id = Guid.NewGuid();
            if (id == Guid.Empty)
                id = Guid.NewGuid();
            return id;
        }

        public void Delete<T>(Guid entityId) where T : DomainBase
        {
            database.ExecuteNonQuery(DataMapper.DeleteCommand<T>());
        }

        public bool Modify<T>(T entity) where T : DomainBase
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            return database.ExecuteNonQuery(DataMapper.ModifyCommand<T>()) == 1;
        }

        public IEnumerable<T> GetAll<T>() where T : DomainBase
        {
            using (IDataReader reader = database.ExecuteReader(DataMapper.SelectAllCommand<T>()))
            {
                var v = reader.ReadAll();
                return (v == null || v.Count() == 0) ? null : v.Select<IDataRecord, T>(rec => DataMapper.Map<T>(rec));
            }
        }

        public T GetById<T>(Guid entityId) where T : DomainBase
        {
            using (IDataReader reader = database.ExecuteReader(DataMapper.SelectByIDCommand<T>()))
            {
                var v = reader.FirstOrDefault();
                return v == null ? null : DataMapper.Map<T>(reader.FirstOrDefault());
            }
        }
    }
}